#include <iostream>
#include <string>

// 模板元编程 O(0)：全都是在编译期进行计算，不是在运行期 

#if 0
    template<int N>
    struct Case {};

    // 特化
    template<>
    struct Case<1>
    {
        // 定义一个静态函数：不需要定义对象就可以直接调用的函数
        static std::string value()
        {
            return "1";
        }
    };

    template<>
    struct Case<2>
    {
        static std::string value()
        {
            return "2";
        }
    };

    int main()
    {
        // 通过模板操作获得了一个条件分支（这个值是在编译期就获取了的，可以通过这种方式进行switch case的模拟）
        std::cout << Case<1>::value() << std::endl;
        std::cout << Case<2>::value() << std::endl;
        return 0;
    }
#endif

#if 0
    template<int N>
    struct Case {};

    // 特化
    template<>
    struct Case<1>
    {
        // 定义一个静态函数：不需要定义对象就可以直接调用的函数
        static std::string value()
        {
            return "1";
        }
    };

    template<>
    struct Case<2>
    {
        static std::string value()
        {
            return "2";
        }
    };

    int main()
    {
        // const是在编译器期就定下来的变量，所以它能够直接作为模板参数传递给它
        // 这能够实现在编译期直接进行分支判断和计算的功能
        const int a = 1; 
        std::cout << Case<a>::value() << std::endl;
        return 0;
    }
#endif

#if 0
    // 模拟for循环
    // 模板元编程的时间复杂度是运行时的O(0)，编译时的O(n),运行期不需要用任何时间，因为它是编译期触发的
    template<int start, int end>
    struct For 
    {
        static void value()
        {
            std::cout << start << std::endl;
            For<start + 1, end>::value();
        }
    };

    // 偏特化
    template <int End>
    struct For<End, End>
    {
        static void value()
        {

        }
    };

    int main()
    {
        For<0, 5>::value();
        return 0;
    }
#endif

#if 1
    // 编译期求斐波那契数列
    template<int N>
    struct data
    {
        // 求斐波那契数列得把值存下来，但是所有的值都有内存
        // 有内存的值存不下来，因为要在编译期去运行它，所以不可能存下来
        // const也不行，因为const是常量，改不了
        // 要在编译期计算并且递归出来
        // 枚举：编译的时候自己做加加计算，所以可以用枚举值来存储数据
        enum // 能够在编译期做加法
        {
            res = data<N - 1>::res + data<N - 2>::res
        };
    };

    // 1的时候要特化
    template<>
    struct data<0>
    {
        enum // 能够在编译器做加法
        {
            res = 0
        };
    };

    template<>
    struct data<1>
    {
        enum // 能够在编译器做加法
        {
            res = 1
        };
    };

    int main()
    {
        std::cout << data<7>::res << std::endl;
        return 0;
    }
#endif